package io.kiki.sba.registry.client.provider;

import io.kiki.sba.registry.client.api.ClientConfig;
import io.kiki.sba.registry.client.api.ConfigDataObserver;
import io.kiki.sba.registry.client.api.Configurator;
import io.kiki.sba.registry.client.api.model.ConfigData;
import io.kiki.sba.registry.client.api.registration.ConfiguratorRegistration;
import io.kiki.sba.registry.client.model.ConfiguratorData;
import io.kiki.sba.registry.client.task.TaskEvent;
import io.kiki.sba.registry.client.task.Worker;
import io.kiki.sba.registry.core.constants.EventTypeConstants;
import io.kiki.sba.registry.core.model.ConfiguratorRegister;
import io.kiki.sba.registry.core.model.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;

@Setter
@Getter

public class ConfiguratorImpl extends AbstractInternalRegister implements Configurator {
    private final String REGIST_ID;

    private ConfiguratorRegistration configuratorRegistration;

    private ConfigDataObserver configDataObserver;

    private ClientConfig clientConfig;

    private ConfiguratorData configuratorData;

    private Worker worker;

    private AtomicBoolean init = new AtomicBoolean(false);


    public ConfiguratorImpl(ConfiguratorRegistration configuratorRegistration, ClientConfig clientConfig, Worker worker) {
        if (null != configuratorRegistration) {
            this.configDataObserver = configuratorRegistration.getConfigDataObserver();
        }
        this.configuratorRegistration = configuratorRegistration;
        this.clientConfig = clientConfig;
        this.worker = worker;
        this.REGIST_ID = UUID.randomUUID().toString();
    }


    @Override
    public ConfigDataObserver getDataObserver() {
        return configDataObserver;
    }


    @Override
    public void setDataObserver(ConfigDataObserver configDataObserver) {
        this.configDataObserver = configDataObserver;
    }


    @Override
    public ConfigData peekData() {
        if (!init.get()) {
            throw new IllegalStateException("Config data is not ready yet.");
        }
        if (null != configuratorData) {
            Data data = configuratorData.getData();
            if (null != data) {
                return new DefaultConfigData(data.getData());
            }
        }
        return new DefaultConfigData(null);
    }


    @Override
    public Object assembly() {
        readLock.lock();
        ConfiguratorRegister configuratorRegister = new ConfiguratorRegister();
        try {
            configuratorRegister.setRegistId(REGIST_ID);
            setAttributes(configuratorRegistration, configuratorRegister, clientConfig);
            // auth signature
            setAuthSignature(configuratorRegister);

            if (isEnabled()) {
                configuratorRegister.setEventType(EventTypeConstants.REGISTER);
            } else {
                configuratorRegister.setEventType(EventTypeConstants.UNREGISTER);
            }
        } finally {
            readLock.unlock();
        }
        return configuratorRegister;
    }


    public void putConfiguratorData(ConfiguratorData receivedConfigData) {
        writeLock.lock();
        try {
            if (null == receivedConfigData) {
                return;
            }

            // default version set to zero
            if (null == receivedConfigData.getVersion()) {
                receivedConfigData.setVersion(0L);
            }

            if (null == configuratorData || receivedConfigData.getVersion() > configuratorData.getVersion()) {
                configuratorData = receivedConfigData;
                init.compareAndSet(false, true);
            }

        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public String getDataId() {
        return configuratorRegistration.getDataId();
    }


    @Override
    public String getGroup() {
        return configuratorRegistration.getGroup();
    }


    @Override
    public String getRegistId() {
        return REGIST_ID;
    }


    @Override
    public void unregister() {
        if (isEnabled()) {
            super.unregister();
            this.worker.schedule(new TaskEvent(this));
        }
    }


}
